﻿using UnityEngine;
using System.Collections.Generic;
using UBlockly.UI;
using UBlockly.Graphic;
using System.Reflection;
using System.Text;
using System;

namespace UBlockly.Scriptable
{
    public static class TranslateHelper
    {
        public static List<BlockDescribeData> TryParse(Type type)
        {
            if (!typeof(IBlockApi).IsAssignableFrom(type))
            {
                throw new System.Exception($"TryParse error,type {type} is not assignableFrom iblockapi");
            }
            var methods = type.GetMethods();
            List<BlockDescribeData> list = new List<BlockDescribeData>();
            foreach (var item in methods)
            {
                var bfa = item.GetCustomAttributes(typeof(BlockDescribeAttribute), false);
                if (bfa == null || bfa.Length == 0)
                {
                    continue;
                }
                BlockDescribeAttribute bfff = bfa[0] as BlockDescribeAttribute;
                BlockDescribeData bd = TryParse(bfff.Classify, item, bfff.BlockDesc);
        
                list.Add(bd);
            }
            return list;
        }
        public static BlockDescribeData TryParse(int classify, MethodInfo method, params string[] descs)
        {
            //函数块默认生成的形状只有两种
            //item.ReturnType = 
            if (!IsBlockMethod(method))
                throw new Exception($"Block函数{method.Name}定义错误");
            var functionDefineStr = ParseMethodToFuncDefineStr(method);
            return new BlockDescribeData(functionDefineStr,classify, descs);
        }
        public static bool IsBlockMethod(MethodInfo method)
        {
            if (!typeof(IVarObject).IsAssignableFrom(method.ReturnType))
            {
                Debug.LogWarning($"函数{method.Name}返回值类型不是IVarObject类型");
                return false;
            }
            foreach (var pp in method.GetParameters())
            {
                if (!typeof(IVarObject).IsAssignableFrom(pp.ParameterType))
                {
                    Debug.LogWarning($"函数{method.Name}参数类型不是IVarObject类型");
                    return false;
                }
            }
            return true;
        }
        //将函数转化成为对应的函数字符串 =》  $"{funcReturn} {funcName}({paramStr})";
        public static string ParseMethodToFuncDefineStr(MethodInfo method)
        {
            string funcReturn = method.ReturnType.ToString();
            funcReturn = funcReturn.Substring(funcReturn.LastIndexOf('.') + 1);
            string funcName = method.Name;
            string paramStr = "";
            var param = method.GetParameters();
            for (int i = 0; i < param.Length; i++)
            {
                string target = "";
                if (TryParseParameterInfo(param[i], ref target))
                {
                    paramStr += $"{target} {param[i].Name},";
                }
            }
            if (!string.IsNullOrEmpty(paramStr))  //去掉','
            {
                paramStr = paramStr.Substring(0, paramStr.Length - 1);
            }

            var targetFuncStr = $"{funcReturn} {funcName}({paramStr})";
            Debug.LogError("target = " + targetFuncStr);
            return targetFuncStr;
        }

        //将参数转化成对应字符串 
        static bool TryParseParameterInfo(ParameterInfo param,ref string target)
        {
            if (param.ParameterType == typeof(VoidR))
                throw new System.Exception("函数参数不能为VoidR类型");
            target = param.ParameterType.Name;
            return !string.IsNullOrEmpty(target);
        }

        public static List<BlockDescribeData> TryParse<T>()
        {
            return TryParse(typeof(T));
        }

        public static Type GetVarTypeByVarTypeName(string varTypeName)
        {
            try
            {
                return Assembly.GetExecutingAssembly().GetType($"UBlockly.Scriptable.{varTypeName}");
            }
            catch (Exception e)
            {
                Debug.LogError($"GetVarTypeByVarTypeName {varTypeName} error");
                throw;
            }
        }
        /// <summary>
        /// block变量名字转成变量枚举
        /// </summary>
        /// <param name="varTypeName"></param>
        /// <returns></returns>
        public static ILVarType GetILVarTypeByVarTypeName(string varTypeName)
        {
            var index = varTypeName.LastIndexOf('R');
            varTypeName = varTypeName.Length == index ? varTypeName : varTypeName.Substring(0, index+1);
            return (ILVarType)System.Enum.Parse(typeof(ILVarType), varTypeName);
        }

        public static Type GetTypeByVarTypeName(string varTypeName)
        {
            try
            {
                return Assembly.GetExecutingAssembly().GetType($"UBlockly.Scriptable.{varTypeName}");
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }
            
        }
        /// <summary>
        /// 获取变量类型名的code
        /// </summary>
        /// <param name="varTypeName"></param>
        /// <returns></returns>
        public static uint GetILVarTypeCodeByVarTypeName(string varTypeName)
        {
            var str = GetILVarTypeByVarTypeName(varTypeName).ToString();
            str = varTypeName.Replace(str, "");
            if (string.IsNullOrEmpty(str))
                return 0;
            return uint.Parse(str);
        }

        /// <summary>
        /// 获取函数名字
        /// </summary>
        /// <param name="funcDefineStr"></param>
        /// <returns></returns>
        public static string ParseFuncName(string funcDefineStr)
        {
            var len = funcDefineStr.IndexOf('(') - funcDefineStr.IndexOf(" ");
            var name = funcDefineStr.Substring(funcDefineStr.IndexOf(" ") + 1, len - 1);
            return name.Trim();
        }
        
        /// <summary>
        /// 把函数定义字符串转成类型字符串
        /// </summary>
        /// <param name="funcDefineStr"></param>
        /// <returns></returns>
        public static string ParseFuncTypeStr(string funcDefineStr)
        {
            string resultTypeStr = funcDefineStr.Substring(0, funcDefineStr.IndexOf('('));
            string paramStr = funcDefineStr.Replace(resultTypeStr, "");
            resultTypeStr = resultTypeStr.Substring(0, resultTypeStr.IndexOf(' '));
            paramStr = paramStr.Replace('(', ' ');
            paramStr = paramStr.Replace(')', ' ');
            paramStr = paramStr.Trim();
            
            string ilfuncTypeStr = GetILVarTypeByVarTypeName(resultTypeStr).ToString();
            if (!string.IsNullOrEmpty(paramStr))
            {
                //IntR-1 test1,IntR-2
                var ppStr = paramStr.Split(',');
                if (ppStr == null)
                    ppStr = new string[1] { paramStr };
                for (int i = 0; i < ppStr.Length; i++)
                {
                    ilfuncTypeStr += "_";
                    var anyP = ppStr[i];
                    anyP = anyP.Trim();
                    anyP = anyP.Substring(0, anyP.IndexOf(' '));
                    ilfuncTypeStr += GetILVarTypeByVarTypeName(anyP).ToString();
                }
            }
//            else
//            {
//                ilfuncTypeStr = $"{ilfuncTypeStr}_{ILVarType.VoidR.ToString()}";
//            }

            return ilfuncTypeStr;
        }


        #region  解析执行
        public static string TranslateNodeToScript(Node node)
        {
            return "敬请期待";
//            var paramstack = NodeStack(node);
//            if (paramstack != null && paramstack.Count > 0)
//            {
//                var p = paramstack.Pop();
//                var getter = p.Scriptable.GetFunc().DefaultParamGetter;
//                object defaultParam = null;
//                if (getter != null)
//                    defaultParam = getter();
//                string target = p.Scriptable.ToILCallFormat(defaultParam);
//                while (paramstack.Count != 0)
//                {
//                    p = paramstack.Pop();
//                    target = p.Scriptable.ToILCallFormat(target);
//                }
//                return target;
//            }
//            return "";
        }

        public static string TranslateChainToScript(LinkedList<Node> chain)
        {
            LinkedListNode<Node> p = chain.First;
            StringBuilder sb = new StringBuilder();
            while (p != null)
            {
                sb.Append(TranslateNodeToScript(p.Value));
                p = p.Next;
            }
            return sb.ToString();
        }
        public static BlockILFunc TranslateNodeToIL(Node node)
        {
            if (node is ComplexNode)
            {
                return node.Scriptable.GetFunc() as BlockILFunc;
            }
            else
            {
                //把对应node生成一颗执行树，然后获取树的根函数
                return RuntimeTreeNode.NodeTree(node).GetTreeFunc();   
            }
        }

        public static void RunNode(UBlockEntry entry,Node node,bool asChain = false)
        {
            if (!asChain)
            {
                var func = TranslateNodeToIL(node);
                func.Excute(entry.EntryHash);
            }
            else
            {
                LinkedList<Node> list = node.Block.Node.List;
                if (list == null)
                {
                    RunNode(entry,node, false);
                }
                else
                {
                    RunChain(entry,list);
                }
            }
        }

        public static void RunChain(UBlockEntry entry, LinkedList<Node> list)
        {
            Queue<Node> que = new Queue<Node>(list.Count);
            foreach (var item in list)
            {
                if (item.Scriptable.ResultType != ILVarType.VoidR)
                {
                    Debug.LogError("严重错误，RunChain 遇到非空类型节点");
                    continue;
                }
                que.Enqueue(item);
            }
            RunNode(entry,que.Dequeue(), que);
        }

        public static List<ILFunc> TranslateChainToIL(LinkedList<Node> chain)
        {
            List<ILFunc> list = new List<ILFunc>(chain.Count);
            var p = chain.First;
            while (p != null)
            {
                list.Add(TranslateNodeToIL(p.Value));
                p = p.Next;
            }
            return list;
        }
        static void RunNode(UBlockEntry entry, Node node, Queue<Node> que)
        {
            if (node == null)
                return;
            var ilFunc = TranslateNodeToIL(node);
            entry.NodeHandlerSystem.NodeBeginExcute(node.Block);
            ilFunc.Excute(entry.EntryHash,() =>
            {
                entry.NodeHandlerSystem.NodeEndExcute(node.Block);
                if (que.Count != 0)
                {
                    RunNode(entry,que.Dequeue(), que);
                }
            });
        }
        #endregion
    }
}

